﻿Shader "Hidden/Clouds"
{
        Properties {
		_CloudThickness("云层厚度", Range(0, 1.0)) = 1.0
         _SunColor("太阳色",Color)=(1., 1., 0.4,1.0)
	     _SunRayColor("太阳辉光色",Color)=(1., 0.7, 0.2,1.0)
	
	     _SkyCtrl("中午亮度控制", Range(1,4)) = 1
 
	     _CloudColor("云层基本色",Color)=(0.05, 0.066, 0.09,1.0)
	     /*_RayleighCoefficientR("瑞利散射R", Range(0,2)) = 1
	     _RayleighCoefficientG("瑞利散射G", Range(0,2)) = 1
	     _RayleighCoefficientB("瑞利散射B", Range(0,2)) = 1*/
	     _RayleighCoefficient("瑞利散射", Range(0,2)) = 1
        _MieCoefficient("米氏散射", Range(0,1)) = 1
	    
		_TimeScale("时间缩放", Range(1, 1000.0)) = 1.0
	 
	    /*A("控制对比度", Range(2,3)) = 2.51
	    B("调整亮度", Range(0,0.1)) = 0.03
	    C("控制对比度", Range(2,3)) = 2.43
	    D("控制高光", Range(0,1)) = 0.59
	    E("控制低光", Range(0,1)) = 0.14*/

	    //_ACESCtrl("_ACESCtrl", Range(0,1)) = 0.5
	    //float3(0.05, 0.066, 0.09)
 
	    atmoDepth("atmoDepth", Range(822,20000)) = 8228
 
	    mieDepth("mieDepth", Range(10,18000)) = 1800
	    ozoneHeight("ozoneHeight", Range(3000,300000)) = 30000
		_yScale("yScale",Range(0.1,3)) = 1.6
		 _Fade("_Fade", Range(0,1)) = 0.1
	 
		[Toggle]_MatCap("_MatCap",int) = 0
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;


            #define sunColor float3(0.95, 0.96, 1.2)
		//uniform float4 sunColor;
        #define FAR 30.

		//#define atmoDepth 8228.
		#define earthRadius 6371000.
		//#define mieDepth 1800
		//#define ozoneHeight 30000.
		float atmoDepth;
 
		float mieDepth;
		float ozoneHeight;

		#define ozoneCoefficient (float3(3.426, 8.298, 0.356)*0.00006*0.01)
		
		
		float4 _SunColor;
		float4 _SunRayColor;
		float _SkyCtrl;
		float _CloudThickness; // 新增云层厚度属性
		uniform float _MieCoefficient;
		/*uniform float _RayleighCoefficientR;
		uniform float _RayleighCoefficientG;
		uniform float _RayleighCoefficientB;*/
		uniform float _RayleighCoefficient;
		uniform half4 _CloudColor;
 
		static float3 rayleighCoefficient = float3(0.0000056, 0.0000125, 0.000029);
	  
		#define mieCoefficient 0.000016*_MieCoefficient
		//uniform float3 _LightDirection;

		static const float fov = 1.3;
		static float3 lgt = normalize(float3(0., 0.27, -0.9));
		static float3 lcol = ((float3)0);
		float3x3 rot_y(float a)
		{
			float sa = sin(a);
			float ca = cos(a);
			return transpose(float3x3(ca, 0., sa, 0., 1., 0., -sa, 0., ca));
		}

			 

		 

		float3 sunPos(float toD, float toY)
		{
			toY = 1. - abs(frac(toY) - 0.5)*2.;
			float mid = 1. - abs(toY - 0.5)*2.;
			float k = lerp(0.68, 1.5, toY);
			float xk = pow(toD, k);
			toD = xk / (xk + pow(1. - toD, k));
			toD = -toD * 6.283853 - 1.5708 + 0.1;
			return normalize(float3(sin(toD)*lerp(0.4, 0.7, mid) + lerp(0.1, -0.1, toY), sin(toD) + lerp(-0.7, 0.69, toY), cos(toD)));
		}

		float3 intcPlane(float3 ro, float3 rd, float plH)
		{
			ro.y += plH;
			float t = -ro.y / rd.y;
			if (t < 0.)
				return ((float3)1000000.);

			float u = ro.x + rd.x*t;
			float v = ro.z + rd.z*t;
			return float3(t, u, v);
		}

		static const float3x3 m3x = mul(transpose(float3x3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339)),2.01);
		float4 cloudMap(float3 p, float time)
		{
			p.xz += float2(-time * 1., time*0.25);
			time *= 0.25;
			p.y -= 9.;
			p *= float3(0.19, 0.3, 0.19)*0.45;
			float3 bp = p;
			float rz = 0.;
			float3 drv = ((float3)0.);
			float z = 0.5;
			float trk = 0.9;
			float dspAmp = 0.2;
			float att = clamp(1.31 - abs(p.y - 5.5)*0.095, 0., 1.);
			float off = dot(sin(p*0.52)*0.7 + 0.3, cos(p.yzx*0.6)*0.7 + 0.3)*0.75 - 0.2;
			float ofst = 12.1 - time * 0.1;
			for (int i = 0; i < 6; i++)
			{
				p += sin(p.yzx*trk - trk * 2.)*dspAmp;
				float3 c = cos(p);
				float3 s = sin(p);
				float3 cs = cos(p.yzx + s.xyz + ofst);
				float3 ss = sin(p.yzx + s.xyz + ofst);
				float3 s2 = sin(p + s.zxy + ofst);
				float3 cdrv = (c*(cs - s * ss) - s * ss.yzx - s.zxy*s2)*z;
				rz += (dot(s, cs) + off - 0.1)*z;
				rz *= att;
				drv += cdrv;
				p += cdrv * 0.05;
				p.xz += time * 0.1;
				dspAmp *= 0.7;
				z *= 0.57;
				trk *= 2.1;
				p = mul(p,m3x);
			}
			return float4(rz*_CloudThickness, drv);
		}

		static float2x2 m2w = mul(transpose(float2x2(0.90475, 0.42594, -0.42594, 0.90475)),2.12);
		float waterDsp(float2 p, float time)
		{
			float rz = 0.;
			float z = 0.4;
			float trk = 1.;
			float dspAmp = 0.5;
			for (int i = 0; i < 5; i++)
			{
				p += sin(p.yx*0.5*trk + trk * 2.5)*dspAmp;
				rz += pow(abs(dot(cos(p*0.37), sin(p - time * 0.5*trk))*z), 1.2);
				z *= 0.49;
				trk *= 1.35;
				dspAmp *= 0.8;
				p = mul(p,m2w);
			}
			return rz;
		}

		static float ttime = 0.;
		static const float3x3 m3 = mul(transpose(float3x3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339)),2.1);
		void cyclicOctave(inout float3 p, inout float rz, inout float z, inout float trk, inout float dspAmp)
		{
			p += sin(p.yzx*0.25*trk - trk * 6.1 + cos(p*0.1 + 0.5)*1.)*dspAmp;
			float ofst = 4.6;
			float3 s = sin(p*1.3);
			rz += smoothstep(-1.1, 0.5, dot(s, cos(p.yzx*0.95 + s.xyz + ofst)))*z;
			dspAmp *= 0.65;
			trk *= 0.35;
			z *= 0.5;
			p = mul(p,m3);
		}

		float cyclic3D(float3 p)
		{
			float3 bp = p;
			float rz = 0.;
			float3 drv = ((float3)0);
			float z = 1.44;
			float trk = 1.;
			float dspAmp = 1.;
			for (int i = 0; i <= 10; i++)
			{
				cyclicOctave(p, rz, z, trk, dspAmp);
			}
			rz -= 1.1;
			return rz;
		}

		float cyclic3DSimp(float3 p)
		{
			float3 bp = p;
			float rz = 0.;
			float z = 1.44;
			float trk = 1.;
			float dspAmp = 1.;
			for (int i = 0; i <= 5; i++)
			{
				cyclicOctave(p, rz, z, trk, dspAmp);
			}
			rz -= 1.1;
			return rz;
		}

		float map(float3 p)
		{
			float d = p.y;
			d -= sin(p.z*0.2 + 1. - cos(p.x*0.25))*0.35;
			float att = clamp(p.y*0.3 + 1.3, 0., 1.);
			d += cyclic3D(p*0.3)*att*1. + 1.;
			return d;
		}

		float mapSimp(float3 p)
		{
			float d = p.y;
			d -= sin(p.z*0.2 + 1. - cos(p.x*0.25))*0.35;
			float att = clamp(p.y*0.3 + 1.3, 0., 1.);
			d += cyclic3DSimp(p*0.3)*att*1. + 1.;
			return d;
		}

#define ITR 120
	 
		static float dfog = 0.;
		static float matid = 0.;
		float curvM(in float3 p, in float w, float3 n, float d)
		{
			float3 haf = normalize(lerp(float3(0, 1, 0), n, 0.5));
			float t1 = map(p + n * w*0.02*d);
			float t2 = map(p - n * w*0.02*d);
			float t3 = map(p + haf * w*0.25);
			float t4 = map(p - haf * w*0.25);
			float t5 = map(p + haf * w*1.3);
			float t6 = map(p - haf * w*1.3);
			float t7 = map(p + float3(0.001, 1, 0.001)*w*20.);
			float t8 = map(p - float3(0.001, 1, 0.001)*w*20.);
			float t0 = map(p);
			float d2 = d * d;
			return smoothstep(-0.55, 0.85, 800.*(t1 + t2) / d2 + 100.*(t3 + t4) / d2 + 2.5*(t5 + t6) + 0.15*(t7 + t8) - 40.*t0)*2.7 - 0.4;
		}

		float3 normal(const in float3 p)
		{
			float2 e = float2(-1., 1.)*0.005;
			return normalize(e.yxx*map(p + e.yxx) + e.xxy*map(p + e.xxy) + e.xyx*map(p + e.xyx) + e.yyy*map(p + e.yyy));
		}

		 

				
		float3 getThickness(float3 rd)
		{
			const float4 cns = earthRadius + float4(atmoDepth, mieDepth, ozoneHeight, ozoneHeight + atmoDepth);
			const float r2 = earthRadius * earthRadius;
			float b = -rd.y*earthRadius;
			float4 z = sqrt(cns*cns + (b*b - r2));
			return float3(b + z.xy, z.w - z.z);
		}


				 
				
		float4 getSky(float3 rd, float3 lgt, float addDepth)
		{
			const float3 addCol = float3(1., 1., 1.);
			const float3x3 coeffs = transpose(float3x3(rayleighCoefficient, ((float3)mieCoefficient), ozoneCoefficient)) / 0.693147;
			float3 thickness = getThickness(rd) + addDepth * addCol;
			float rdl = max(dot(rd, lgt), 0.);
			float3 rayleighScatter = thickness.x*(0.4*rdl*rdl + 1.12)*rayleighCoefficient;
			float g = 0.8 - lgt.y*0.15 - mieCoefficient * 1500.;
			float g2 = g * g;
			float a = rsqrt(g2 - (2.*g*rdl - 1.));
			float phaseMie = (0.4 + lgt.y*0.1 + mieCoefficient * 7000.)*(1. - g2)*a*a*a;
			float mieScatter = thickness.y*phaseMie*mieCoefficient;
			float3 sunCoeff = mul(coeffs,getThickness(lgt) + addDepth * addCol);

			
			float3 viewCoeff = mul(coeffs,thickness);
			float3 absorption = (exp2(-viewCoeff) - exp2(-sunCoeff)) / ((sunCoeff - viewCoeff)*0.693147);
 
			float4 skyColor =  float4(clamp(sunColor*(rayleighScatter + mieScatter)*absorption*(0.6 + lgt.y*0.3), 0., 100.5), sunCoeff.r);


			float t = max(lgt.y,0);
			skyColor.b  *= lerp(1,_SkyCtrl,t*t)  ;
			 
			return skyColor;
		}
		
		float3 getSun(float3 rd, float sunCoeff)
		{
			float rdl = max(dot(rd, lgt), 0.);
			float dcy = smoothstep(-0.05, 0.2, lgt.y);
			float3 sun = 50.*_SunColor.rgb*pow(rdl, 10000.)*clamp(1. - dcy * 0.7, 0., 1.);
			sun += 10.*_SunRayColor.rgb*pow(rdl, 3500.);
			sun *= clamp(1. - dcy * 0.6, 0., 1.);
			sun *= exp2(-sunCoeff * 0.45);
			return sun;
		}

		float linstep(in float mn, in float mx, in float x)
		{
			return clamp((x - mn) / (mx - mn), 0., 1.);
		}

		float2x2 rot2(in float a)
		{
			float c = cos(a), s = sin(a);
			return transpose(float2x2(c, s, -s, c));
		}
		float _TimeScale;
		float4 getClouds(in float3 ro, in float3 rd, float scnD, float3 skyCol)
		{
			float4 rez = ((float4)0.);
			float t = min(intcPlane(ro, rd, -12.).x, 175.);
	 
			float sunUp = max(lgt.y,0.0);
			float sunUp3 = clamp(sunUp*sunUp*sunUp*6., 0., 1.);
			float sunDw = 1. - sunUp;
			sunDw = pow(sunDw, 6.);
			float bsd = dot(lgt.xz, rd.xz);
			float sd = max(bsd, 0.);
			float sd2 = max(bsd*0.55 + 0.53, 0.);
			float3 topSky = clamp(getSky(float3(0, 1, 0), lgt, 0.).xyz, 0., 1.);
			float3 baseCol = lerp(topSky, _CloudColor.rgb , clamp(sunUp3, 0., 0.6))*0.2;

		 
			float extraDepth = 140000.*((1. - bsd)*0.2 + 0.9)*pow(1. - sunUp, 4.) ;
			float3 hlitCol = clamp(getSky(normalize(mul(lgt - float3(0, 0.001, 0),rot_y(0.15))), lgt, extraDepth).xyz, 0., 1.);
			hlitCol = hlitCol * sd2*lerp(sunDw, sunDw*sunDw, sd)*8.;
			float3 bSkyCol = getSky(rd, lgt, extraDepth*5.*(sunUp*0.8 + 0.2)).xyz;
			float3 sunLCol = lerp(float3(1., 0.8, 0.75), ((float3)0.5), sunUp);
			
			float3 atmoCol = lerp(bSkyCol*(sunUp*0.3 + 0.7), sunLCol*dot(bSkyCol, ((float3)0.38)), sunUp3)*0.25;
	 
			hlitCol = bSkyCol;
		 
			float time = _Time.y*_TimeScale;
			for (int i = 0; i < 30; i++)
			{
				float3 pos = ro + t * rd;
				if (rez.a > 0.99 || t > 300. || pos.y > 150.)
					break;

				float4 cld = cloudMap(pos, time);
				float den = clamp(cld.x, 0., 1.)*1.02;
				float dn = clamp(cld.x + 1.9, 0., 3.);
				float fogT = 0.;
				float4 col = ((float4)0.);
				if (cld.x > 0.6)
				{
					col = float4(baseCol, 0.1);
					float nl = 0.3;
					 
					float dif = clamp((cld.x - cloudMap(pos + lgt * 8., time).x)*0.4 + 0.2, 0.11, 2.)*2.5;
					dif += clamp((cld.x - cloudMap(pos + lgt * 15., time).x)*0.2 - 0.03, -0.02, 1.)*4.;
					col.rgb += atmoCol * ((nl*0.25 + 0.7)*dif*0.65);
					float den2 = den * den;
					float den4 = den2 * den2;
					col *= den4 * den4;
					//col.rgb += col.a*clamp((nl*0.8 + 0.1)*dif, 0., 1.)*hlitCol;
				}

				float fogC = exp2(t*0.012 / (rd.y + 0.35) - 11.7);
				//col.rgba += float4(skyCol, 1.)*clamp(fogC, 0., 1.);
				rez = rez + col * (1. - rez.a);
				t += clamp(7. - dn * dn*0.85, 1.2, 7.);
			}
			return clamp(rez, 0., 1.);
		}
		 
		 float _Fade;
		 float _yScale;
		float modifyColor(float t)
		{
			float s= 0.4;
			if(t>s)
			{
				t =  s+smoothstep(s,1.0,t) * (1-s)*0.5;
			}
			return t;
		}
		float4 render(in float3 ro, in float3 rd)
		{
				 
		 
			float ldt = clamp(dot(lgt, rd), 0., 1.);

			float4 skyCol = getSky(rd, lgt, 0.);
			float3 col = skyCol.rgb ;
			
			  
	 
			float3 bg = col;
			float3 lgtOffs = normalize(lgt + float3(0, 0.03, 0.));
			float4 haloCol = getSky(lgtOffs, lgt, 0.);
			lcol = clamp(lerp(haloCol.xyz, float3(0.72, 0.71, 0.7), clamp(lgt.y*3., 0.04, 0.9)), 0., 1.);

			 
			float4 cld = getClouds(ro, rd, 10000., bg);
			
			col = col * (1. - cld.w) + cld.xyz;
			
			
			return float4(cld.xyz,1);		 
				 
				 
			return float4(col, 1.0);
				 
					
					
		}
		
 
		 
		/*uniform float A  ;  // 控制对比度
		uniform	float B  ;  // 调整亮度
		uniform	float C  ;  // 控制对比度
		uniform	float D  ;  // 控制高光
		uniform	float E  ;  // 控制低光*/
		float3 tonemapACES(float3 color)
		{
			float A = 2.51;  // 控制对比度
			float B = 0.03;  // 调整亮度
			float C = 2.43;  // 控制对比度
			float D = 0.59;  // 控制高光
			float E = 0.14;  // 控制低光

			// 使用 ACES 映射公式
			return saturate((color * (A * color + B)) / (color * (C * color + D) + E));
		}

		inline float3 FromRadialCoords(float2 uv)
		{
			float2 sphereCoords = float2(0.5, 1.0) - uv;

			float longitude = sphereCoords.x * (2.0 * UNITY_PI);  // [-π, π]
			float latitude = sphereCoords.y * UNITY_PI;           // [0, π]

			float y = cos(latitude);
			float sinLat = sin(latitude);
			float x = cos(longitude) * sinLat;
			float z = sin(longitude) * sinLat;

			return float3(x, y, z);
		}
			float _MatCap;



		 
float2 DirToMatCapUV(float3 dir, float yScale)
{
          // 保证输入是单位向量
    dir.y *= yScale;              // 压缩 Y 分量，增强平视区域密度

	dir = normalize(dir);   
    float2 uv = dir.xz  ;
    return uv * 0.5 + 0.5;
}

float3 MatCapUVToDir(float2 uv, float yScale)
{
	float3 dir;
    dir.xz  = uv.xy * 2 - 1;
	// 计算dir.xz自身的点积
	float dotResult = dot(dir.xz, dir.xz);
	// 确保1.0 - dotResult是非负的
	dir.y = sqrt(max(0.0, 1.0 - dotResult));
	dir.y/=yScale;
   return normalize( dir) ;
}
 
            fixed4 frag (v2f i) : SV_Target
            {
				float2 uv = i.uv.xy;
				//uv.y=uv.y*0.5+uv.y;
				uv.y =uv.y*0.5+0.5;
                float3 dir = FromRadialCoords(uv);
                
				if(_MatCap)
				{
					dir = MatCapUVToDir(i.uv.xy,_yScale);
					 
					/*dir.xz  = i.uv.xy * 2 - 1;
					// 计算dir.xz自身的点积
					float dotResult = dot(dir.xz, dir.xz);
					// 确保1.0 - dotResult是非负的
					dir.y = sqrt(max(0.0, 1.0 - dotResult));*/

				}

				//rayleighCoefficient*=float3(_RayleighCoefficientR,_RayleighCoefficientG,_RayleighCoefficientB);
				rayleighCoefficient*= _RayleighCoefficient;

				lgt = _WorldSpaceLightPos0.xyz;
				
				float3 ro = 0;
				float3 rd = dir;
		 
				 
				float4 fragColor = render(ro, rd);

				float f  = smoothstep(0,_Fade, rd.y);
				if(_MatCap)
				fragColor *= f*f;
			 
 
			 
		 
				fragColor.rgb = tonemapACES(fragColor.rgb);
				fragColor.rgb = clamp(fragColor.rgb,0,1);
				fragColor.x = modifyColor(fragColor.x);
			    fragColor.y = modifyColor(fragColor.y);
			    fragColor.z = modifyColor(fragColor.z);
			 
				return fragColor;
              
            }
            ENDCG
        }
    }
}
